/****************************************************************************

	COPYRIGHT(C) MAXSI SOFTWARE, JONAS 'SORTIE' TERMANSEN 2008, 2009, 2010

    This file is part of Maxsi Distribution.

    Maxsi Distribution is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Maxsi Distribution is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with Maxsi Distribution. If not, see <http://www.gnu.org/licenses/>.

	*/ #include "MaxsiDistributionContributors.h" /*

	If you modify this file, please enter your name below and provide contact
	information in MaxsiDistributionContributors.h. For more information please see
	MaxsiDistributionContributors.h.
	
	Contributors to this file:

	- Jonas 'Sortie' Termansen
	- [your name here]

	MaxsiDistribution.dll
	Distributing since 2008

	MaxsiFileServer.h
	Async File Handling

****************************************************************************/

#ifndef MaxsiFileServer_H
#define MaxsiFileServer_H

	// TODO: CHANGE FILE SIZES FROM SIZE_T TO __INT64 SO WE SUPPORT REALLY LARGE STRUCTURES!
	// TODO: REMOVE OLD OUTCOMMENTED CODE!

	// Modes
	#define FileServer_Inactive					(0x0000000)	//	Nothing's going on.
	#define FileServer_ReadingCommand			(0x0000001)	//	Figuring out what's going on
	#define FileServer_FileOpen					(0x0000002)	//	A file is open.
	//#define Torrent_InCommand					(0x0000003)	//	Exectuing a command.


	#define FileServer_CommandWrite				(0x0000001)	//	Write to a file
	#define FileServer_CommandDecompressTorrent	(0x0000002)	//	Decompress Torrent Data
	
	class	MaxsiTorrentData;
	class	ME_TorrentServerClient;
	struct	MaxsiTorrentBlock;

	struct	ME_FileServerClientCommand
	{
		bool	Read;
		int		A;
		int		B;
		int		C;
		int		D;
		int		E;
	};
	
	
	// Classes
	class	ME_FileServerClient;

	class ME_FileServerClient : public ME_ServerClient
	{
		Declare_Class(ME_FileServerClient, ME_ServerClient);

	public:
		ME_FileServerClient();
		~ME_FileServerClient();

		virtual		bool	Init();				// Attach to a new client
		virtual		bool	Close();			// Detach from a client

#ifdef _DEBUG
					int		LastThinkType;
		virtual		bool	ScheduledNextThink(int NextThinkType, int Line, char* FileName);
#endif

		virtual		bool	InitializeBuffers();

		//virtual		bool	OnRecieved(size_t Length); // When Length bytes are recieved
		//virtual		bool	Read(size_t Keep); // Read more data, but keep the last Keep bytes of the previous read.

		virtual		bool	Open(char* File, DWORD Access, DWORD Flags = FILE_ATTRIBUTE_NORMAL);
		virtual		bool	Opened();

		virtual		bool	MaintainConnection();

		// TODO: Perhaps move to MaxsiEngine::ME_ServerClient?
		virtual		bool	Think();	
		virtual		bool	ThinkModeFileServer_Inactive();
		virtual		bool	ThinkModeFileServer_ReadingCommand();	
		virtual		bool	ThinkModeFileServer_FileOpen();		
		virtual		bool	ThinkModeFileServer_FileOpen_CommandWrite();		
		virtual		bool	ThinkModeFileServer_FileOpen_CommandDecompressTorrent();		



		// See ME_FileServer::AsyncWriteTorrentBlock()
		virtual	bool		AsyncWriteTorrentBlock(
			MaxsiTorrentData* TorrentData,
			MaxsiTorrentBlock* Block,
			ME_TorrentServerClient* Client,
			char* Buffer,
			size_t Offset,
			size_t BlockSize,
			size_t BufferSize,
			bool Compressed);

		// See ME_FileServer::FullTorrentBlockRecieved()
		virtual bool		FullTorrentBlockRecieved(
			MaxsiTorrentData* TorrentData,
			MaxsiTorrentBlock* Block,
			ME_TorrentServerClient* Client,
			bool Compressed);

		virtual	void		CALLBACK DoneIO(
			DWORD dwErrorCode,
			DWORD dwNumberOfBytesTransferred,
			LPOVERLAPPED lpOverlapped);

		//virtual		size_t		IN_BUFFER_SIZE( void );
		//virtual		size_t		IN_BUFFER_INC( void );
		//virtual		size_t		OUT_BUF_SIZE( void );

		// Replaced with the ME_Buffer class:

		//virtual		size_t		GetBufferOffset();
		//virtual		size_t		GetBufferUsed();
		//virtual		size_t		GetBufferAvailable();

		//virtual		bool		GetBufferData(void* dest, size_t Length);
		//virtual		bool		SetBufferData(void* src, size_t Length);

	public:	

		// Replaced with improved security in ME_ServerClient and ME_Buffer:

//		// Thread safety
//		virtual		void	Enter();
//		virtual		void	Leave();
//#ifdef _DEBUG
//		size_t				nL_MayWriteToBlocks;
//#endif
//		CRITICAL_SECTION	MayWriteToBlocks;
//		CRITICAL_SECTION	MayExecThinkFunction;


	public:
		//int							Mode;
		//int							Command;
		ME_FileServerClientCommand	CommandParam;
		char*						CurrentFile;
		//size_t						BufferOffset;
		//size_t						BufferUsed;
		//size_t						CurrentlyWriting;
		bool						BufferOverflowDetected;

		// Replaced with internal sanity test in ME_ServerClient::DoThink()

//#ifdef _DEBUG
//		size_t						Insanity;
//#endif
	};

	// Overlapped I/O: Completion Ports
	class ME_FileServer : public ME_IOCPServer
	{
		Declare_Class(ME_FileServer, ME_IOCPServer);
	public:
		ME_FileServer();
		~ME_FileServer();

	public:
		virtual	bool	HandleRequest		(ME_ServerClient* Client, char* Parameter = 0);

		virtual	bool	RunServer(short Port);
		virtual	bool	RunServerEx(short Port, size_t NumConnections, size_t CheckTime);

		virtual			ME_ServerClient*	CreateIOCPClient	(void);
		virtual			bool				OnClientCreated		(ME_ServerClient* Client);
		virtual			bool				OnClientConnected	(SOCKET s, int Errror);

		// Request the write of a torrent block to disk when possible. If the output buffer is full,
		// the function returns false and the OnBufferExpanded callback function will be called
		// when buffer has been expanded or parts of it is freed. Then try again.
		// If the data is successfully copied to the output buffer the function returns true and will be
		// written when possible.
		// If the Compressed flag is set, the data is first copied to a temporary .MaxsiDistribution file
		// and later uncompressed when the FullTorrentBlockRecieved() function is called.
		virtual	bool		AsyncWriteTorrentBlock(
			MaxsiTorrentData* TorrentData,
			MaxsiTorrentBlock* Block,
			ME_TorrentServerClient* Client,
			char* Buffer,
			size_t Offset,
			size_t BlockSize,
			size_t BufferSize,
			bool Compressed);
		
		// Requests the decompression of a compressed torrent block. Call this function after
		// each part of the file has been written using AsyncWriteTorrentBlock().
		// If the output buffer is full, the function returns false and the OnBufferExpanded
		// callback function will be called when buffer has been expanded or parts of it is 
		// freed. Then try again. If the request is successful, this function returns true.
		// If the file isn't compressed, nothing will happen and the function returns true.
		virtual bool		FullTorrentBlockRecieved(
			MaxsiTorrentData* TorrentData,
			MaxsiTorrentBlock* Block,
			ME_TorrentServerClient* Client,
			bool Compressed);

	public:
		// Callback functions!
		DECLARE_FUNCTION(bool, OnBufferExpanded,	(ME_FileServer* Updated));

	};

	#ifdef max
	#undef max
	#endif
	#define max(a,b)            (((a) > (b)) ? (a) : (b))

	#ifdef min
	#undef min
	#endif
	#define min(a,b)            (((a) < (b)) ? (a) : (b))

	
#endif